package routing

import (
	"net/http"
	"net/url"
	"path"
	"regexp"
	"strings"
)

/**
 * 路由解析
 * @param req *http.Request
 * @return interface{}
 */
func (rt *Rtr) Match(req *http.Request) interface{} {

	_routes := rt.routes[req.Method]

	if nil != _routes {
		if _route := match(_routes, req); nil != _route {
			return _route
		}
	}

	return rt.getBye(req.Method)
}

/**
 * 路由匹配
 * @param routes []*Route
 * @return *Route
 */
func match(routes []*Route, req *http.Request) *Route {

	_host, _port := getHost(req)
	_path, _ext := getPath(req)

	for _, _route := range routes {

		if false == through(_route.GetHost(), _host) {
			continue
		}

		if false == through(_route.GetPort(), _port) {
			continue
		}

		if false == through(_route.GetExt(), _ext) {
			continue
		}

		//静态路由
		if _route.GetPath() == _path {
			return _route
		}

		//没有冒号(:)直接跳过
		if 0 > strings.Index(_route.GetPath(), ":") {
			continue
		}

		_regex, _keys := getRegex(_route)

		_match := _regex.FindStringSubmatch(_path)

		if nil != _match {
			for _index, _value := range _keys {
				_route.Param(_value, _match[_index])
			}

			return _route
		}
	}

	return nil
}

/**
 * 判断是否满足条件
 * @param array []string
 * @param val string
 * @return bool
 */
func through(array []string, val string) bool {

	if 0 == len(array) || "" == val {
		return true
	}

	for _, value := range array {
		if strings.ToLower(value) == strings.ToLower(val) {
			return true
		}
	}

	return false
}

/**
 * 返回正则表达式
 * @param r route
 * @return string, []string
 */
func getRegex(r *Route) (*regexp.Regexp, []string) {

	_pattern := r.GetPattern()
	_keys := []string{}
	_path := strings.Replace(r.GetPath(), "/", "\\/", -1)

	for _k, _v := range _pattern {
		if 0 < strings.Count(_path, ":"+_k) {
			_keys = append(_keys, _k)
			_path = strings.Replace(_path, ":"+_k, "("+_v+")", -1)
		}
	}

	_regex := regexp.MustCompile("^" + _path + "$")

	return _regex, _keys
}

/**
 * 返回路径信息
 * @param req *http.Request
 * @return string, string
 */
func getPath(req *http.Request) (string, string) {

	//将请求地址转为小写
	_path := strings.ToLower(req.URL.Path)
	_ext := path.Ext(_path)

	if "" != _ext {
		_path = strings.TrimSuffix(_path, _ext)
	}

	return strings.TrimRight(_path, "/"), _ext
}

/**
 * 返回查询参数
 * @param req *http.Request
 * @return url.Values, error
 */
func getQuery(req *http.Request) (url.Values, error) {
	return url.ParseQuery(req.URL.RawQuery)
}

/**
 * 返回主机和端口
 * @param req *http.Request
 * @return string, string
 */
func getHost(req *http.Request) (string, string) {

	if -1 != strings.Index(req.Host, ":") {
		result := strings.Split(req.Host, ":")
		return result[0], result[1]
	}

	return req.Host, ""
}
